<?php

namespace Jingdong\Callback;

/**
 * 京东配送回调SDK
 * 
 * 用于向海博技术服务平台发送京东配送订单状态变更、骑手信息变更、费用信息变更等回调
 * 
 * @package Jingdong\Callback
 * @version 1.0.0
 * @author SDK Team
 */
class JingdongCallbackSDK
{
    /**
     * 版本号
     */
    const VERSION = '1.0.0';
    
    /**
     * 海博技术服务平台回调接口地址
     */
    const CALLBACK_URL_TEST = 'https://pre-carrieropen.hiboos.com/api/delivery/statusCallback';
    const CALLBACK_URL_SANDBOX = 'https://carrieropen-tool.hiboos.com/api/delivery/statusCallback';
    const CALLBACK_URL_PROD = 'https://carrieropen.hiboos.com/api/delivery/statusCallback';
    
    /**
     * 请求超时时间（秒）
     */
    const TIMEOUT = 120;
    
    /**
     * 重试次数
     */
    const MAX_RETRY = 3;
    
    /**
     * 京东接口返回结果Code
     */
    const ERROR_SUCCESS = 0;
    const ERROR_SYSTEM_ERROR = 1;
    const ERROR_PARAM_ERROR = 2;
    const ERROR_SIGN_ERROR = 3;
    const ERROR_UNAUTHORIZED = 4;
    const ERROR_RATE_LIMIT = 5;
    const ERROR_OTHER = 9;
    const ERROR_NO_CAPACITY = 10;
    const ERROR_ORDER_NOT_EXIST = 101;
    const ERROR_ORDER_COMPLETED = 102;
    const ERROR_SERVICE_NOT_OPEN = 103;
    const ERROR_OUT_OF_RANGE = 104;
    const ERROR_APPOINTMENT_TIME = 105;
    const ERROR_CAPACITY_SHORTAGE = 106;
    const ERROR_ACCOUNT_BALANCE = 107;
    const ERROR_NO_APPOINTMENT = 108;
    const ERROR_NO_REVERSE_ORDER = 109;
    const ERROR_TIP_LIMIT = 110;
    const ERROR_TIP_MAX = 111;
    const ERROR_NO_RIDER_LOCATION = 112;
    const ERROR_CARRIER_MISMATCH = 301;
    const ERROR_DELIVERY_ID_MISMATCH = 302;
    const ERROR_WAYBILL_NOT_EXIST = 303;
    const ERROR_RIDER_CODE_ERROR = 501;
    const ERROR_RIDER_LIMIT = 502;
    const ERROR_RIDER_CANNOT_ACCEPT = 503;
    const ERROR_FEATURE_NOT_OPEN = 504;
    const ERROR_STORE_CREATE_FAILED = 601;
    const ERROR_STORE_NO_CHANGE = 602;
    
    /**
     * 配置信息
     */
    private $config;
    
    /**
     * Redis连接
     */
    private $redis;
    
    /**
     * 日志回调函数
     */
    private $logger;
    
    /**
     * 构造函数
     * 
     * @param array $config 配置信息
     */
    public function __construct($config = [])
    {
        $this->config = array_merge([
            'developer_id' => '',
            'secret' => '',
            'environment' => 'test', // test, sandbox, prod
            'redis_config' => null,
            'enable_log' => true,
            'user_agent' => 'JingdongCallbackSDK-PHP/' . self::VERSION
        ], $config);
        
        $this->validateConfig();
        $this->initRedis();
    }
    
    /**
     * 验证配置
     */
    private function validateConfig()
    {
        if (empty($this->config['developer_id'])) {
            throw new \InvalidArgumentException('developer_id 不能为空');
        }
        
        if (empty($this->config['secret'])) {
            throw new \InvalidArgumentException('secret 不能为空');
        }
        
        if (!in_array($this->config['environment'], ['test', 'sandbox', 'prod'])) {
            throw new \InvalidArgumentException('environment 必须为 test, sandbox, prod 之一');
        }
    }
    
    /**
     * 初始化Redis连接
     */
    private function initRedis()
    {
        if (!$this->config['redis_config']) {
            return;
        }
        
        try {
            if (!extension_loaded('redis')) {
                $this->log('warning', 'Redis扩展未安装，将跳过防重复检查');
                return;
            }
            
            $redisConfig = array_merge([
                'host' => '127.0.0.1',
                'port' => 6379,
                'database' => 0,
                'password' => '',
                'timeout' => 3.0
            ], $this->config['redis_config']);
            
            $this->redis = new \Redis();
            $connected = $this->redis->connect($redisConfig['host'], $redisConfig['port'], $redisConfig['timeout']);
            
            if (!$connected) {
                throw new \Exception('Redis连接失败');
            }
            
            if (!empty($redisConfig['password'])) {
                $this->redis->auth($redisConfig['password']);
            }
            
            $this->redis->select($redisConfig['database']);
            $this->log('info', 'Redis连接成功');
            
        } catch (\Exception $e) {
            $this->log('error', 'Redis连接失败: ' . $e->getMessage());
            $this->redis = null;
        }
    }
    
    /**
     * 设置日志回调函数
     * 
     * @param callable $logger 日志回调函数，接收参数：($level, $message, $context)
     */
    public function setLogger($logger)
    {
        $this->logger = $logger;
    }
    
    /**
     * 记录日志
     * 
     * @param string $level 日志级别
     * @param string $message 日志消息
     * @param array $context 上下文信息
     */
    private function log($level, $message, $context = [])
    {
        if (!$this->config['enable_log']) {
            return;
        }
        
        if ($this->logger && is_callable($this->logger)) {
            call_user_func($this->logger, $level, $message, $context);
        } else {
            // 默认输出到error_log
            $logMessage = sprintf('[%s] [%s] %s', date('Y-m-d H:i:s'), strtoupper($level), $message);
            if (!empty($context)) {
                $logMessage .= ' ' . json_encode($context, JSON_UNESCAPED_UNICODE);
            }
            error_log($logMessage);
        }
    }
    
    /**
     * 发送订单状态回调
     * 
     * @param array $order 订单信息
     * @param int $status 新状态
     * @param array $extraParams 额外参数
     * @return array 返回结果
     */
    public function sendStatusCallback($order, $status, $extraParams = [])
    {
        try {
            // 防重复机制检查
            $isTransfer = isset($extraParams['isTransfer']) && $extraParams['isTransfer'] === true;
            
            if (!$isTransfer && $this->redis) {
                $deduplicationKey = "jd_callback_sent_" . $order['id'] . "_" . $status;
                
                if ($this->redis->exists($deduplicationKey)) {
                    $lastSentInfo = json_decode($this->redis->get($deduplicationKey), true);
                    $this->log('info', '京东状态回调防重复跳过', [
                        'order_id' => $order['id'],
                        'status' => $status,
                        'last_sent' => $lastSentInfo['sent_at'] ?? 'unknown'
                    ]);
                    
                    return [
                        'success' => true,
                        'message' => '防重复跳过发送',
                        'data' => $lastSentInfo,
                        'deduplicated' => true
                    ];
                }
                
                // 记录本次发送
                $sendInfo = [
                    'order_id' => $order['id'],
                    'status' => $status,
                    'sent_at' => date('Y-m-d H:i:s'),
                    'timestamp' => time(),
                    'is_transfer' => false
                ];
                $this->redis->setex($deduplicationKey, 30, json_encode($sendInfo));
            }
            
            // 构建回调参数
            $params = $this->buildCallbackParams($order, $status, $extraParams);
            
            // 发送回调
            $result = $this->sendCallback($params);
            
            // 更新Redis缓存记录成功结果
            if ($this->redis) {
                $deduplicationTime = $isTransfer ? 5 : 30;
                $keyPrefix = $isTransfer ? "jd_transfer_sent_" : "jd_callback_sent_";
                $deduplicationKey = $keyPrefix . $order['id'] . "_" . $status;
                
                $successInfo = [
                    'order_id' => $order['id'],
                    'status' => $status,
                    'sent_at' => date('Y-m-d H:i:s'),
                    'timestamp' => time(),
                    'result' => $result,
                    'success' => true,
                    'is_transfer' => $isTransfer
                ];
                $this->redis->setex($deduplicationKey, $deduplicationTime, json_encode($successInfo));
            }
            
            $this->log('info', '海博技术服务平台回调发送成功', [
                'order_id' => $order['id'],
                'platform_order_no' => $order['platform_order_no'] ?? '',
                'status' => $status,
                'result' => $result
            ]);
            
            return ['success' => true, 'message' => '回调发送成功', 'data' => $result];
            
        } catch (\Exception $e) {
            // 清理Redis缓存，允许重试
            if ($this->redis) {
                $isTransfer = isset($extraParams['isTransfer']) && $extraParams['isTransfer'] === true;
                $keyPrefix = $isTransfer ? "jd_transfer_sent_" : "jd_callback_sent_";
                $deduplicationKey = $keyPrefix . $order['id'] . "_" . $status;
                $this->redis->del($deduplicationKey);
            }
            
            $this->log('error', '海博技术服务平台回调发送失败', [
                'order_id' => $order['id'] ?? '',
                'platform_order_no' => $order['platform_order_no'] ?? '',
                'status' => $status,
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ]);
            
            return ['success' => false, 'message' => '回调发送失败: ' . $e->getMessage()];
        }
    }
    
    /**
     * 构建回调参数
     * 
     * @param array $order 订单信息
     * @param int $status 状态
     * @param array $extraParams 额外参数
     * @return array 回调参数
     */
    private function buildCallbackParams($order, $status, $extraParams = [])
    {
        // 获取当前时间作为操作时间
        $operateTime = time();
        
        // 业务参数
        $businessParams = [
            'orderId' => isset($order['platform_order_no']) ? $order['platform_order_no'] : $order['order_no'],
            'carrierDeliveryId' => $order['order_no'],
            'carrierShopId' => $order['jd_store_id'],
            'carrierMerchantId' => isset($order['carrier_merchant_id']) ? $order['carrier_merchant_id'] : 'HBT_JZD',
            'status' => $status,
            'operateTime' => $operateTime
        ];
        
        // 根据状态添加必要的骑手信息
        $riderRequiredStatuses = [20, 25, 30, 50];
        if (in_array($status, $riderRequiredStatuses)) {
            // 检查是否为转单操作
            if (isset($extraParams['isTransfer']) && $extraParams['isTransfer'] === true) {
                $businessParams['riderName'] = $extraParams['newRiderName'] ?? '';
                $businessParams['riderPhone'] = $extraParams['newRiderPhone'] ?? '';
                $businessParams['riderPhoneType'] = 0;
            } else {
                // 从订单信息获取骑手信息
                if (isset($order['rider_name'])) {
                    $businessParams['riderName'] = $order['rider_name'];
                }
                if (isset($order['rider_phone'])) {
                    $businessParams['riderPhone'] = $order['rider_phone'];
                    $businessParams['riderPhoneType'] = 0;
                }
            }
            
            // 处理位置信息
            if (isset($businessParams['riderName'])) {
                // 优先使用extraParams中的位置
                if (isset($extraParams['riderLng']) && isset($extraParams['riderLat'])) {
                    $businessParams['riderLng'] = $this->formatCoordinate($extraParams['riderLng']);
                    $businessParams['riderLat'] = $this->formatCoordinate($extraParams['riderLat']);
                } elseif (isset($order['rider_lng']) && isset($order['rider_lat'])) {
                    $businessParams['riderLng'] = $this->formatCoordinate($order['rider_lng']);
                    $businessParams['riderLat'] = $this->formatCoordinate($order['rider_lat']);
                } else {
                    // 使用默认位置（北京天安门）
                    $businessParams['riderLng'] = 116397470;
                    $businessParams['riderLat'] = 39908860;
                }
                
                // 验证并调整经纬度范围
                $businessParams = $this->validateCoordinates($businessParams);
            }
        }
        
        // 取消状态的特殊处理
        if ($status == 99) {
            $businessParams['cancelReasonCode'] = $extraParams['cancelReasonCode'] ?? 99;
            $businessParams['cancelReasonDesc'] = $extraParams['cancelReasonDesc'] ?? '其他原因取消';
            
            if (isset($extraParams['cancelFee'])) {
                $businessParams['cancelFee'] = floatval($extraParams['cancelFee']);
            }
        }
        
        // 费用信息
        if (isset($order['fee']) && is_array($order['fee'])) {
            $fee = $order['fee'];
            
            if (isset($fee['actual_amount'])) {
                $businessParams['actualFee'] = floatval($fee['actual_amount']);
            } elseif (isset($fee['total_amount'])) {
                $businessParams['actualFee'] = floatval($fee['total_amount']);
            }
            
            if (isset($fee['toll_fee']) && $fee['toll_fee'] > 0) {
                $businessParams['tollFee'] = floatval($fee['toll_fee']);
            }
            if (isset($fee['handling_fee']) && $fee['handling_fee'] > 0) {
                $businessParams['handlingFee'] = floatval($fee['handling_fee']);
            }
            if (isset($fee['waiting_fee']) && $fee['waiting_fee'] > 0) {
                $businessParams['waitingFee'] = floatval($fee['waiting_fee']);
            }
            if (isset($fee['parking_fee']) && $fee['parking_fee'] > 0) {
                $businessParams['parkingFee'] = floatval($fee['parking_fee']);
            }
        }
        
        // 订单图片信息
        if (isset($extraParams['orderImages']) && !empty($extraParams['orderImages'])) {
            if (is_array($extraParams['orderImages'])) {
                $businessParams['orderImages'] = json_encode($extraParams['orderImages'], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
            } else {
                $businessParams['orderImages'] = $extraParams['orderImages'];
            }
        }
        
        // 添加公共参数
        $commonParams = [
            'developerId' => $this->config['developer_id'],
            'timestamp' => time(),
            'version' => '1.0'
        ];
        
        // 合并参数
        $allParams = array_merge($commonParams, $businessParams);
        
        // 生成签名
        $allParams['sign'] = $this->generateSign($allParams);
        
        return $allParams;
    }
    
    /**
     * 生成签名
     * 
     * @param array $params 请求参数
     * @return string 签名
     */
    private function generateSign($params)
    {
        // 移除签名参数
        unset($params['sign']);
        
        // 过滤空值参数
        $filteredParams = [];
        foreach ($params as $key => $value) {
            if ($value !== '' && $value !== null && $value !== [] && (!is_string($value) || strlen($value) > 0)) {
                $filteredParams[$key] = $value;
            }
        }
        
        // 按参数名字典顺序排序
        ksort($filteredParams);
        
        // 拼接参数字符串
        $stringToBeSigned = '';
        foreach ($filteredParams as $key => $value) {
            if (is_bool($value)) {
                $value = $value ? 'true' : 'false';
            } elseif (is_array($value) || is_object($value)) {
                $value = json_encode($value, JSON_UNESCAPED_UNICODE);
            } else {
                $value = (string)$value;
            }
            $stringToBeSigned .= $key . $value;
        }
        
        // 加上secret前缀
        $stringToBeSigned = $this->config['secret'] . $stringToBeSigned;
        
        // SHA1加密并转小写
        return strtolower(sha1($stringToBeSigned));
    }
    
    /**
     * 发送回调请求
     * 
     * @param array $params 回调参数
     * @return array 响应结果
     */
    private function sendCallback($params)
    {
        $retry = 0;
        $lastError = null;
        
        while ($retry < self::MAX_RETRY) {
            try {
                if ($retry > 0) {
                    $this->log('info', '京东回调重试', [
                        'retry' => $retry,
                        'order_id' => $params['orderId'] ?? '未知',
                        'status' => $params['status'] ?? '未知'
                    ]);
                }
                
                $url = $this->getCallbackUrl();
                $ch = curl_init();
                
                curl_setopt_array($ch, [
                    CURLOPT_URL => $url,
                    CURLOPT_POST => true,
                    CURLOPT_POSTFIELDS => http_build_query($params),
                    CURLOPT_HTTPHEADER => [
                        'Content-Type: application/x-www-form-urlencoded',
                        'User-Agent: ' . $this->config['user_agent'],
                        'Accept: application/json'
                    ],
                    CURLOPT_TIMEOUT => self::TIMEOUT,
                    CURLOPT_CONNECTTIMEOUT => 10,
                    CURLOPT_RETURNTRANSFER => true,
                    CURLOPT_FOLLOWLOCATION => true,
                    CURLOPT_SSL_VERIFYPEER => false,
                    CURLOPT_SSL_VERIFYHOST => false
                ]);
                
                $requestStartTime = microtime(true);
                $response = curl_exec($ch);
                $requestDuration = round((microtime(true) - $requestStartTime) * 1000, 2);
                
                $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
                $curlError = curl_error($ch);
                $curlErrorNo = curl_errno($ch);
                curl_close($ch);
                
                $this->log('info', '海博技术服务平台回调HTTP请求详情', [
                    'url' => $url,
                    'duration_ms' => $requestDuration,
                    'http_code' => $httpCode,
                    'retry' => $retry
                ]);
                
                if ($curlError) {
                    throw new \Exception('网络连接异常: ' . $curlError . ' (错误代码: ' . $curlErrorNo . ')');
                }
                
                if ($httpCode !== 200) {
                    throw new \Exception('HTTP状态码错误: ' . $httpCode . ', 响应: ' . $response);
                }
                
                $result = json_decode($response, true);
                if (json_last_error() !== JSON_ERROR_NONE) {
                    throw new \Exception('响应数据格式错误: ' . json_last_error_msg() . ', 原始响应: ' . $response);
                }
                
                if (isset($result['code']) && $result['code'] == 0) {
                    if ($retry > 0) {
                        $this->log('info', '京东回调重试成功', [
                            'retry' => $retry,
                            'order_id' => $params['orderId'] ?? '未知',
                            'status' => $params['status'] ?? '未知'
                        ]);
                    }
                    return $result;
                } else {
                    $errorCode = $result['code'] ?? -1;
                    $errorMsg = $result['message'] ?? '未知错误';
                    
                    // 检查是否是不需要重试的错误码
                    $noRetryErrorCodes = [
                        self::ERROR_CARRIER_MISMATCH,
                        self::ERROR_DELIVERY_ID_MISMATCH,
                        self::ERROR_WAYBILL_NOT_EXIST
                    ];
                    
                    if (in_array($errorCode, $noRetryErrorCodes)) {
                        $errorDesc = $this->getErrorDescription($errorCode);
                        throw new \Exception('海博技术服务平台接口返回不重试错误: [' . $errorCode . '] ' . $errorDesc . ' - ' . $errorMsg);
                    }
                    
                    $errorDesc = $this->getErrorDescription($errorCode);
                    throw new \Exception('海博技术服务平台接口返回错误: [' . $errorCode . '] ' . $errorDesc . ' - ' . $errorMsg);
                }
                
            } catch (\Exception $e) {
                if (strpos($e->getMessage(), '不重试错误') !== false) {
                    throw $e;
                }
                
                $lastError = $e;
                $retry++;
                
                if ($retry < self::MAX_RETRY) {
                    sleep($retry);
                }
            }
        }
        
        throw new \Exception('回调发送失败，已重试' . self::MAX_RETRY . '次: ' . $lastError->getMessage());
    }
    
    /**
     * 获取回调URL
     * 
     * @return string
     */
    private function getCallbackUrl()
    {
        switch ($this->config['environment']) {
            case 'prod':
                return self::CALLBACK_URL_PROD;
            case 'sandbox':
                return self::CALLBACK_URL_SANDBOX;
            case 'test':
            default:
                return self::CALLBACK_URL_TEST;
        }
    }
    
    /**
     * 格式化坐标为京东API格式
     * 
     * @param mixed $coordinate 坐标值
     * @return int 格式化后的坐标
     */
    private function formatCoordinate($coordinate)
    {
        if (is_numeric($coordinate)) {
            $coord = floatval($coordinate);
            // 如果已经是*10^6格式的整数，直接返回
            if (abs($coordinate) > 1000000) {
                return intval($coordinate);
            }
            // 否则转换为*10^6格式
            return intval($coord * 1000000);
        }
        return 0;
    }
    
    /**
     * 验证并调整坐标范围
     * 
     * @param array $params 包含坐标的参数
     * @return array 调整后的参数
     */
    private function validateCoordinates($params)
    {
        if (!isset($params['riderLng']) || !isset($params['riderLat'])) {
            return $params;
        }
        
        // 处理负数经度
        if ($params['riderLng'] < 0) {
            $params['riderLng'] = 360000000 + $params['riderLng'];
        }
        
        // 验证经度范围 (0 < lng < 360000000)
        if ($params['riderLng'] <= 0 || $params['riderLng'] >= 360000000) {
            $params['riderLng'] = 116397470; // 北京天安门
        }
        
        // 验证纬度范围 (-90000000 < lat < 90000000)
        if ($params['riderLat'] < -90000000 || $params['riderLat'] > 90000000) {
            $params['riderLat'] = 39908860; // 北京天安门
        }
        
        return $params;
    }
    
    /**
     * 获取错误码描述
     * 
     * @param int $errorCode 错误码
     * @return string 错误描述
     */
    private function getErrorDescription($errorCode)
    {
        $errorMap = [
            self::ERROR_SUCCESS => '请求成功',
            self::ERROR_SYSTEM_ERROR => '系统异常',
            self::ERROR_PARAM_ERROR => '缺少参数，或参数格式错误',
            self::ERROR_SIGN_ERROR => '签名验证失败',
            self::ERROR_UNAUTHORIZED => '未授权或授权过期',
            self::ERROR_RATE_LIMIT => '接口流控',
            self::ERROR_OTHER => '其他原因',
            self::ERROR_NO_CAPACITY => '该地区暂无运力',
            self::ERROR_ORDER_NOT_EXIST => '订单不存在',
            self::ERROR_ORDER_COMPLETED => '订单已完成，不能取消',
            self::ERROR_SERVICE_NOT_OPEN => '门店未开通所选服务产品',
            self::ERROR_OUT_OF_RANGE => '送货地址超出配送范围',
            self::ERROR_APPOINTMENT_TIME => '预约时间内无法完成履约',
            self::ERROR_CAPACITY_SHORTAGE => '运力紧张，无法创建订单',
            self::ERROR_ACCOUNT_BALANCE => '账户余额不足或扣款失败',
            self::ERROR_NO_APPOINTMENT => '暂不支持预约单',
            self::ERROR_NO_REVERSE_ORDER => '暂不支持逆向发单',
            self::ERROR_TIP_LIMIT => '骑手已接单，无法添加小费',
            self::ERROR_TIP_MAX => '小费金额已至上限，无法继续添加',
            self::ERROR_NO_RIDER_LOCATION => '骑手目前没有位置信息，请稍后重试',
            self::ERROR_CARRIER_MISMATCH => '配送商不匹配',
            self::ERROR_DELIVERY_ID_MISMATCH => '配送商物流单号不匹配',
            self::ERROR_WAYBILL_NOT_EXIST => '运单不存在',
            self::ERROR_RIDER_CODE_ERROR => '骑手信息错误，请扫正确的骑手码',
            self::ERROR_RIDER_LIMIT => '骑手接单数已超上限',
            self::ERROR_RIDER_CANNOT_ACCEPT => '骑手无法接单',
            self::ERROR_FEATURE_NOT_OPEN => '请联系配送商客服开通功能后使用',
            self::ERROR_STORE_CREATE_FAILED => '暂时无法创建门店或修改门店信息，需要稍后重试',
            self::ERROR_STORE_NO_CHANGE => '此次变更未修改任何门店信息'
        ];
        
        return isset($errorMap[$errorCode]) ? $errorMap[$errorCode] : '未知错误码: ' . $errorCode;
    }
    
    /**
     * 将本地状态转换为京东状态
     * 
     * @param string $localStatus 本地状态
     * @return int 京东状态
     */
    public static function convertLocalStatusToJingdongStatus($localStatus)
    {
        $statusMap = [
            "1"=>1,
            '10' => 10,  // 待接单 => 已创建(待接单)
            '20' => 20,  // 已接单 => 已接单
            '25' => 25,  // 到达取货点 => 已到店
            '30' => 30,  // 配送中 => 已取货
            '50' => 50,  // 已完成 => 已送达
            '99' => 99,  // 已取消 => 已取消
        ];
        
        return isset($statusMap[$localStatus]) ? $statusMap[$localStatus] : 10;
    }
    
    /**
     * 根据取消角色获取京东取消原因代码
     * 
     * @param string $role 取消角色
     * @return int 京东取消原因代码
     */
    public static function getCancelReasonCode($role)
    {
        $reasonMap = [
            'ADMIN' => 1,        // 商户取消
            'CUSTOMER' => 2,     // 用户取消
            'SYSTEM' => 3,       // 系统取消
            'RIDER' => 4,        // 骑手取消
            'CARRIER' => 5,      // 配送商取消
        ];
        
        return isset($reasonMap[$role]) ? $reasonMap[$role] : 99;
    }
    
    /**
     * 根据取消角色获取取消原因描述
     * 
     * @param string $role 取消角色
     * @param string $remark 自定义备注
     * @return string 取消原因描述
     */
    public static function getCancelReasonDesc($role, $remark = '')
    {
        $reasonDesc = [
            'ADMIN' => '商户取消',
            'CUSTOMER' => '用户取消',
            'SYSTEM' => '系统取消',
            'RIDER' => '骑手取消',
            'CARRIER' => '配送商取消',
        ];
        
        $baseDesc = isset($reasonDesc[$role]) ? $reasonDesc[$role] : '其他原因';
        
        if (!empty($remark)) {
            return $baseDesc . '：' . $remark;
        }
        
        return $baseDesc;
    }
    
    /**
     * 测试连通性
     * 
     * @return array 测试结果
     */
    public function testConnectivity()
    {
        $url = $this->getCallbackUrl();
        $host = parse_url($url, PHP_URL_HOST);
        $port = parse_url($url, PHP_URL_PORT) ?: 443;
        
        $results = [];
        
        // DNS解析测试
        $ip = gethostbyname($host);
        $results['dns'] = [
            'host' => $host,
            'ip' => $ip,
            'success' => ($ip !== $host)
        ];
        
        // 端口连通性测试
        $connection = @fsockopen($host, $port, $errno, $errstr, 5);
        $results['port'] = [
            'host' => $host,
            'port' => $port,
            'success' => ($connection !== false),
            'error' => $connection ? null : "$errno: $errstr"
        ];
        if ($connection) {
            fclose($connection);
        }
        
        // HTTP请求测试
        try {
            $ch = curl_init();
            curl_setopt_array($ch, [
                CURLOPT_URL => $url,
                CURLOPT_HEADER => true,
                CURLOPT_NOBODY => true,
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_TIMEOUT => 10,
                CURLOPT_CONNECTTIMEOUT => 5,
                CURLOPT_SSL_VERIFYPEER => false,
                CURLOPT_SSL_VERIFYHOST => false
            ]);
            
            $response = curl_exec($ch);
            $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            $curlError = curl_error($ch);
            $curlErrorNo = curl_errno($ch);
            curl_close($ch);
            
            $results['http'] = [
                'success' => empty($curlError),
                'http_code' => $httpCode,
                'curl_error' => $curlError,
                'curl_errno' => $curlErrorNo
            ];
            
        } catch (\Exception $e) {
            $results['http'] = [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
        
        return $results;
    }
}
